.. :validated: 3.1.0

.. _dbg_secure_protocols:

Безопасный обмен данными с применением SSL/TLS
==============================================================================

Доменный компьютер взаимодействует с подсистемами **ALD Pro** по разным протоколам, некоторые из которых используют шифрование:

* Доступ к каталогу по протоколам **LDAP+StartTLS** (**TCP/389**) и **LDAPS** (**TCP/636**) со стороны службы **SSSD** и с помощью инструментов пакета **ldap-utils**.

* Доступ к веб-интерфейсам контроллера домена по протоколу **HTTPS** (**TCP/443**) с помощью браузера и к **REST API** с помощью утилиты автоматизации **ipa**.

* Доступ к удаленному рабочему столу доменного компьютера с портала управления ALD Pro по протоколу **VNC** через **HTTPS** (**TCP/6080** - **TCP/608x**).

* Аутентификация с использованием расширения **PKINIT** по протоколу **Kerberos** (**TCP/88**) использует **X.509** сертификаты для взаимной аутентификации центра распределения ключей и клиента, но не является примером **SSL**-протокола.

Сертификаты применяются также для доступа к **PostgreSQL** (**TCP/5432**), взаимодействия со службой печати по протоколу **IPP** (**TCP/631**), а до версии 2.0.0 использовалось **REST API** системы конфигурирования **SaltStack** (**TCP/8000**), но все эти примеры не представляют интереса в виду локального характера сетевого взаимодействия.

Механизм защиты данных по протоколу SSL
------------------------------------------------------------------------------

Протокол **SSL** (Secure Sockets Layer, уровень защищенных сокетов) в его текущей реализации **TLS** (Transport Layer Security, безопасность транспортного уровня) обеспечивает быстрый и безопасный обмен данными между клиентом и сервером за счет сочетания симметричных и асимметричных алгоритмов шифрования: медленные асимметричные алгоритмы используются только на фазе рукопожатия для того, чтобы договориться о параметрах шифрования и безопасно обменяться сессионным ключом, а непосредственно обмен данными происходит уже с применением быстрых симметричных алгоритмов.

Разница между этими алгоритмами заключается в том, что симметричные алгоритмы позволяют расшифровать данные тем же ключом, с помощью которого они были зашифрованы, просто выполняя те же действия в обратном порядке, а в асимметричных алгоритмах используется пара взаимосвязанных ключей, поэтому данные, зашифрованные одним из ключей, могут быть расшифрованы только вторым ключом из той же пары.

Суть работы асимметричных алгоритмов можно продемонстрировать на примере из жизни, см. :ref:`рис. 5.14`.

Представьте, что для установления безопасного канала связи нужно обменяться с второй стороной общим кодовым словом. Для этого через службу доставки ей пересылается открытый сейф с самозакрывающимся механизмом, оставляя ключ у себя. Вторая сторона должна будет поместить в этот сейф записку с кодовым словом, защелкнуть замок и переслать сейф обратно. Не взламывая замок, открыть этот сейф можно будет только на вашей стороне, т.к. ключ есть только у вас.

.. figure:: media/46_ssl-handshake-concept.png
    :name: рис. 5.14
    :scale: 50

    Иллюстрация идеи асимметричного шифрования на примере использования сейфа с самозакрывающимся механизмом

Изначально протокол **SSL** разрабатывался для **HTTP**, но его универсальный **TCP**-подобный интерфейс позволил создать расширения и других транспортных протоколов прикладного уровня, например, **LDAPS**, **FTPS**, **SMTPS**, **IMAPS** и др. В качестве примера рассматривается открытие веб-страницы по **HTTPS**, см. :ref:`рис. 5.15`.

.. figure:: media/47_ssl-handshake-flow.png
    :name: рис. 5.15
    :scale: 50

    Установление безопасного HTTPS-соединения

**Шаг (1)** Когда пользователь переходит по **https**-ссылке, браузер выполняет подключение к **веб-серверу** на **TCP/443** порт и передает список поддерживаемых методов шифрования для установления безопасного соединения.

**Шаг (2)** **Веб-сервер** выбирает метод шифрования и передает **клиенту** свой **SSL**-сертификат, который содержит публичный ключ и цифровую подпись для этого ключа. Вернее, он передает не один сертификат, а всю цепочку до корневого сертификата включительно.

**Шаг (3)** **Клиент** проверяет валидность цифровой подписи по своей базе доверенных корневых сертификатов, используя алгоритмы асимметричного шифрования. Также **клиент** проверяет подлинность **сервера**, сопоставляя имя, по которому обращается с именем, указанным внутри сертификата. Если подпись не пройдет проверку, то пользователь получит сообщение о небезопасности соединения ввиду возможности атак посредника (Man in the middle, **MITM**).

**Шаг (4)** **Клиент** генерирует случайный ключ и шифрует его асимметричным алгоритмом - публичным ключом **сервера** для безопасной передачи данных по сети.

**Шаг (5)** **Сервер** передает **клиенту** сообщение, зашифрованное общим ключом, подтверждающее возможность начала безопасного обмена данными.

**Шаг (6)** **Клиент** и **сервер** выполняют обмен данными по защищенному каналу связи.

Доступ к каталогу по протоколам LDAP+StartTLS и LDAPS
------------------------------------------------------------------------------

Служба **SSSD** получает данные из каталога по протоколу **LDAP** (**TCP/389**) с использованием расширения **StartTLS**, которое позволяет инициировать шифрованный обмен данными внутри уже установленного **TCP**-соединения вместо открытия нового соединения на отдельном порту.

Администратор может проверить, что порт **TCP/389** действительно защищен шифрованием, и получить цепочку сертификатов с помощью утилиты **openssl**. Первый сертификат выписан на конкретный FQDN контроллера домена, а второй соответствует корневому сертификату домена.

.. code-block:: bash

    echo Q | openssl s_client -starttls ldap -showcerts dc-1.ald.company.lan:389

Результат выполнения:

.. code-block:: bash

    CONNECTED(00000003)
    depth=1 CN = CA Signing Certificate
    verify return:1
    depth=0 CN = dc-1.ald.company.lan
    verify return:1
    ---
    Certificate chain
    0 s:CN = dc-1.ald.company.lan
    i:CN = CA Signing Certificate
    1 s:CN = CA Signing Certificate
    i:CN = CA Signing Certificate
    ---
    Server certificate
    -----BEGIN CERTIFICATE-----
    MIIDxjCCAq6gAwIBAgIUZ4JathCvRrV6v+Aoi4kUNScViBswDQYJKoZIhvcN
    AQEL
    BQAwITEfMB0GA1UEAwwWQ0EgU2lnbmluZyBDZXJ0aWZpY2F0ZTAeFw0y
    MjExMTYx
    NzM4MjVaFw0zMjExMTMxNzM4MjVaMCExHzAdBgNVBAMMFmRjLTEuY
    WxkLmNvbXBh
    ...
    -----BEGIN CERTIFICATE-----
    MIIDIzCCAgugAwIBAgIUULQd6OzgJ/ik7wJvV0gd6kUIFKAwDQYJKoZIhvcN
    AQEL
    BQAwITEfMB0GA1UEAwwWQ0EgU2lnbmluZyBDZXJ0aWZpY2F0ZTAeFw0y
    MjExMTYx
    NzM4MjVaFw00MjExMTExNzM4MjVaMCExHzAdBgNVBAMMFkNBIFNpZ
    25pbmcgQ2Vy
    ...

Доверие к этой цепочке проверяется с помощью корневого сертификата из файла */etc/ipa/ca.crt*, на который указывает параметр ``ldap_tls_cacert`` из секции **domain** конфигурационного файла */etc/sssd/sssd.conf*. Данный сертификат загружается на компьютер автоматически при вводе компьютера в домен. Содержимое этого файла соответствует последнему сертификату из цепочки, полученной от сервера.

Открыть конфигурацию *sssd.conf* для проверки сертификата:

.. code-block:: bash

    sudo cat /etc/sssd/sssd.conf | grep ldap_tls_cacert

Результат отображает файл */etc/ipa/ca.crt*:

.. code-block:: bash

    ldap_tls_cacert = /etc/ipa/ca.crt

Открыть файл сертификата командой:

.. code-block:: bash

    sudo cat /etc/ipa/ca.crt

В результате отображается сертификат **X509** формате **Base64String**:

.. code-block:: bash

    -----BEGIN CERTIFICATE-----
    MIIDIzCCAgugAwIBAgIUULQd6OzgJ/ik7wJvV0gd6kUIFKAwDQYJKoZIhvcN
    AQEL
    BQAwITEfMB0GA1UEAwwWQ0EgU2lnbmluZyBDZXJ0aWZpY2F0ZTAeFw0y
    MjExMTYx
    NzM4MjVaFw00MjExMTExNzM4MjVaMCExHzAdBgNVBAMMFkNBIFNpZ
    25pbmcgQ2Vy

Проверить содержимое сертификата можно с помощью все той же утилиты **openssl**. Как можно заметить, по умолчанию корневой сертификат выписан на 10 лет, после чего его нужно будет продлевать.

.. code-block:: bash

    sudo openssl x509 -in /etc/ipa/ca.crt -text -noout

Результат выполнения:

.. code-block:: bash

    Certificate:
    Data:
    Version: 3 (0x2)
    Serial Number:
    50:b4:1d:e8:ec:e0:27:f8:a4:ef:02:6f:57:48:1d:ea:45:08:14:a0
    Signature Algorithm: sha256WithRSAEncryption
    Issuer: CN = CA Signing Certificate
    Validity
    Not Before: Nov 16 17:38:25 2023 GMT
    Not After : Nov 11 17:38:25 2043 GMT
    ...

Для упрощения отладки работы компьютеров в домене на них автоматически устанавливается и настраивается пакет **ldap-utils**, в состав которого входят такие утилиты как **ldapsearch**, **ldapadd** и др. Безопасность соединения проверяется с использованием корневого сертификата из файла */etc/ssl/certs/ca-certificates.crt*, на который указывает параметр ``TLS_CACERT`` из конфигурационного файла */etc/ldap/ldap.conf*.

.. code-block:: bash

    sudo cat /etc/ldap/ldap.conf

Результат выполнения:

.. code-block:: bash

    ...
    TLS_CACERT
    /etc/ssl/certs/ca-certificates.crt
    URI ldaps://dc-1.ald.company.lan
    BASE dc=ald,dc=company,dc=lan
    SASL_MECH GSSAPI
    ...

Файл *ca-certificates.crt* является связкой сертификатов, в которой содержится более 100 корневых сертификатов удостоверяющих центров, которым доверяет операционная система Astra Linux. Корневой сертификат домена, который ранее отображался в файле */etc/ipa/ca.crt*, обычно находится в самом конце этого файла. Чтобы просмотреть информацию по всем сертификатам из файла, можно использовать следующую команду:

.. code-block:: bash

    openssl crl2pkcs7 -nocrl -certfile /etc/ssl/certs/ca-certificates.crt | openssl pkcs7 -print_certs -text -noout | less

Если необходимо запретить на КД передачу нешифрованного трафика, выполнить команду:

.. code-block:: bash

    ldapmodify -H ldaps://localhost:636 -D "cn=Directory Manager" -W <<EOF 
    dn: cn=config 
    changetype: modify 
    replace: nsslapd-require-secure-binds 
    nsslapd-require-secure-binds: on 
    EOF

где ``Directory Manager`` — учетная запись (УЗ) под которой вносятся изменения (может быть выбрана другая УЗ на усмотрение пользователя).

Для проверки успешности результата выполнить команду на просмотр текущей конфигурации **LDAP** в части параметра ``nsslapd-require-secure-binds``:

.. code-block:: bash

    ldapsearch -x -u -H ldaps://localhost -b cn=config "(cn=config)" nsslapd-require-secure-binds -W -D "cn=Directory Manager"

Ожидаемый вывод:

.. code-block:: bash

    config dn: cn=config ufn: config nsslapd-require-secure-binds: on

Доступ к веб-интерфейсам и REST API контроллера домена по протоколу HTTPS
------------------------------------------------------------------------------

Портал управления **ALD Pro** и веб-интерфейс **FreeIPA** работают только по безопасному протоколу **HTTPS**, и, если обратиться к контроллеру с помощью утилиты **openssl**, то можно заметить, что веб-сервер **Apache** использует тот же самый сертификат, что и **LDAP-каталог**.

.. code-block:: bash

    echo Q | openssl s_client -showcerts dc-1.ald.company.lan:443

Результат выполнения для сайта **dc-1.ald.company.lan**:

.. code-block:: bash

    -----BEGIN CERTIFICATE-----
    MIIDxjCCAq6gAwIBAgIUZ4JathCvRrV6v+Aoi4kUNScViBswDQYJKoZIhvcN
    AQEL
    BQAwITEfMB0GA1UEAwwWQ0EgU2lnbmluZyBDZXJ0aWZpY2F0ZTAeFw0y
    MjExMTYx
    NzM4MjVaFw0zMjExMTMxNzM4MjVaMCExHzAdBgNVBAMMFmRjLTEuY
    WxkLmNvbXBh
    ...

Проверить сертификат для службы **389 directory server**:

.. code-block:: bash

    echo Q | openssl s_client -showcerts dc-1.ald.company.lan:636

Результат для службы **LDAP-каталога** на **636** порту:

.. code-block:: bash

    ...
    -----BEGIN CERTIFICATE-----
    MIIDxjCCAq6gAwIBAgIUZ4JathCvRrV6v+Aoi4kUNScViBswDQYJKoZIhvcN
    AQEL
    BQAwITEfMB0GA1UEAwwWQ0EgU2lnbmluZyBDZXJ0aWZpY2F0ZTAeFw0y
    MjExMTYx
    NzM4MjVaFw0zMjExMTMxNzM4MjVaMCExHzAdBgNVBAMMFmRjLTEuY
    WxkLmNvbXBh
    ...

Для того, чтобы браузер доменного компьютера открывал эти ресурсы без предупреждений, корневой сертификат ALD Pro должен быть добавлен в хранилище доверенных корневых сертификатов. На контроллерах домена для браузера Firefox это настроено через корпоративную политику, описанную в файле */usr/lib/firefox/distribution/policies.json*. С помощью этой же политики можно разрешить прозрачную Kerberos-аутентификацию для ресурсов из корпоративного домена, для этого нужно в секции **Authentication** задать параметр **SPNEGO** (Simple and Protected GSS-API Negotiation Mechanism, простой и защищенный механизм согласования **GSS-API**). 

Проверить файл командой:

.. code-block:: bash

    cat /usr/lib/firefox/distribution/policies.json

.. code-block:: bash

    {
        "policies": {
            "BlockAboutAddons": true,
            "BlockAboutConfig": true,
            "Authentication": {
                "SPNEGO": ["ald.company.lan"]
            },
            "Certificates": {
                "ImportEnterpriseRoots": true,
                "Install": ["/etc/ipa/ca.crt"]
            },
            "Homepage": {
                "URL": "https://dc-1.ald.company.lan/",
                "Locked": true,
                "StartPage": "homepage-locked"
            }
        }
    }

Для автоматической настройки рабочих станций можно задействовать механизм групповых политик **ALD Pro**:

#. Создать простой дополнительный параметр компьютера «**Политика браузера Firefox**» с уникальным идентификатором **firefox_policy**.

#. Создать внутри этого параметра следующие атрибуты:

    * «Блокировать доступ к странице addons», идентификатор **block_about_addons**;

    * «Блокировать доступ к странице config», идентификатор **block_about_config**;

    * «Список доменов для Kerberos аутентификации», идентификатор **authentication_spnego**;

    * «Список доверенных сертификатов», идентификатор **trusted_certificates**;

    * «Адрес домашней страницы», идентификатор **homepage_url**.

#. Задать текст скрипта:

.. code-block:: bash

    {% set node = salt['grains.get']('nodename') %}
    {% set gpo = salt['pillar.get']('aldpro-hosts:' + node + ':firefox_policy' ) %}
    {% if gpo %}
    firefox_policy:
    file.managed:
        - name: /usr/lib/firefox/distribution/policies.json
        - user: root
        - group: root
        - mode: 644
        - contents:
        - '{'
        - '        "policies": {'
    {% if gpo['block_about_addons'] %}
        - '                "BlockAboutAddons": {{ gpo['block_about_addons'] }},'
    {% endif %}{% if gpo['block_about_config'] %}
        - '                "BlockAboutConfig": {{ gpo['block_about_config'] }},'
    {% endif %}{% if gpo['authentication_spnego'] %}
        - '                "Authentication": {'
        - '                         "SPNEGO": [{{ gpo['authentication_spnego'] }}]'
        - '                },'
    {% endif %}{% if gpo['trusted_certificates'] %}
        - '                "Certificates": {'
        - '                        "ImportEnterpriseRoots": true,'
        - '                        "Install": [{{ gpo['trusted_certificates'] }}]'
        - '                },'
    {% endif %}{% if gpo['homepage_url'] %}
        - '                "Homepage": {'
        - '                        "URL": "{{ gpo['homepage_url'] }}",'
        - '                        "Locked": true,'
        - '                        "StartPage": "homepage-locked"'
        - '                }'
    {% endif %}
        - '        }'
        - '}'
    {% endif %}

Доступ к удаленному рабочему столу по протоколу VNC через HTTPS
------------------------------------------------------------------------------

Для оказания пользователям услуги технической поддержки администратор может подключиться к удаленному рабочему столу компьютера, для этого пользователю нужно запустить приложение «Удаленный рабочий стол» и сообщить администратору случайный пароль из окна приложения. Подключение к сессии выполняется со страницы компьютера на портале управления, функция реализована на базе программного кода из проекта noVNC.

Открывая приложение удаленного рабочего стола, пользователь фактически запускает на своем компьютере упрощенный веб-сервер **websockify**, который перенаправляет запросы на порт **TCP/5900**, где их обрабатывает **x11vnc**-сервер. Веб-серверу порт назначается динамически, начиная с **TCP/6080** в зависимости от того, сколько сессий удаленного подключения было инициировано на рабочей станции. Для безопасного обмена данными **websockify** использует закрытый ключ и **SSL**-сертификат из файла */opt/rbta/aldpro/rd-gui/noVNC/novnc.pem*. Можно проверить, что это именно тот сертификат с помощью утилиты **openssl**.

Вывести сертификат для сравнения на экран:

.. code-block:: bash

    cat /opt/rbta/aldpro/rd-gui/noVNC/novnc.pem

Результат выполнения:

.. code-block:: bash

    -----BEGIN CERTIFICATE-----
    MIIDazCCAlOgAwIBAgIUbKtAWP6659L+jsNqaemnAQVksoswDQYJKoZIhvc
    NAQEL
    BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxI
    TAfBgNVBAoM
    GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMjA2MTQxNzAxMDF
    aFw0yMzA2
    ...

Сверить **SSL**-сертификат на порту **6080** утилитой **openssl**:

.. code-block:: bash

    echo Q | openssl s_client -connect pc-1.ald.company.lan:6080

В результате выполнения команды отображается тот же сертификат:

.. code-block:: bash

    -----BEGIN CERTIFICATE-----
    MIIDazCCAlOgAwIBAgIUbKtAWP6659L+jsNqaemnAQVksoswDQYJKoZIhvc
    NAQEL
    BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxI
    TAfBgNVBAoM
    GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMjA2MTQxNzAxMDF
    aFw0yMzA2
    ...

Подробности об этом сертификате можно посмотреть с помощью той же утилиты:

.. code-block:: bash

    openssl x509 -in /opt/rbta/aldpro/rd-gui/noVNC/novnc.pem -text -noout

Результат выполнения команды это описание сертификата в удобочитаемом формате:

.. code-block:: bash

    Certificate:
        Data:
            Version: 3 (0x2)
            Serial Number:
                6c:ab:40:58:fe:ba:e7:d2:fe:8e:c3:6a:69:e9:a7:01:05:64:b2:8b
            Signature Algorithm: sha256WithRSAEncryption
            Issuer: C = AU, ST = Some-State, O = Internet Widgits Pty Ltd
    ...

Когда администратор подключается к **клиенту** с **веб-портала**, он обращается к URL вида ``wss://dc-1.ald.company.lan/aldpro/rdproxy/pc-1.ald.company.lna/6080/websockify``, поэтому **веб-сервер** **контроллера домена** проксирует запросы на указанный порт доменного компьютера. В конфигурационном файле */etc/apache2/conf-aldpro/aldpro-mp-rdproxy.conf* для параметра **SSLProxyVerify** определено значение ``none``, поэтому принимаются любые самоподписанные сертификаты.